package org.dxy.trigger.http.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dxy.api.dto.request.material.*;
import org.dxy.api.response.R;
import org.dxy.domain.command.material.*;
import org.dxy.domain.handler.material.*;
import org.dxy.infrastructure.persistent.db.mybatispuls.po.query.MaterialViewPo;
import org.dxy.infrastructure.persistent.db.mybatispuls.service.MaterialViewService;
import org.dxy.trigger.http.service.MaterialApplicationService;
import org.dxy.types.common.CommandResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * 物料应用服务实现
 * @author dxy
 * @createTime 2025/9/7
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MaterialApplicationServiceImpl implements MaterialApplicationService {

    // Command Handlers (写操作)
    private final CreateMaterialCommandHandler createMaterialCommandHandler;
    private final UpdateMaterialCommandHandler updateMaterialCommandHandler;
    private final UpdateMaterialSpecificationCommandHandler updateMaterialSpecificationCommandHandler;
    private final UpdateMaterialUnitCommandHandler updateMaterialUnitCommandHandler;
    private final UpdateMaterialCostCommandHandler updateMaterialCostCommandHandler;
    private final EnableMaterialCommandHandler enableMaterialCommandHandler;
    private final DisableMaterialCommandHandler disableMaterialCommandHandler;
    private final DeleteMaterialCommandHandler deleteMaterialCommandHandler;
    
    // Query Service (读操作)
    private final MaterialViewService materialViewService;

    @Transactional
    @Override
    public R<Long> create(CreateMaterialRequest request) {
        try {
            CreateMaterialCommand command = new CreateMaterialCommand(
                    request.getMaterialCode()
            );

            CommandResult<Long> result = createMaterialCommandHandler.handle(command);
            
            if (result.success()) {
                // 保存基础读模型信息
                MaterialViewPo materialView = MaterialViewPo.builder()
                        .id(result.data())
                        .materialCode(request.getMaterialCode())
                        .materialName(request.getMaterialName())
                        .specification(request.getSpecification())
                        .model(request.getModel())
                        .unit(request.getUnit())
                        .groupId(request.getGroupId())
                        .standardCost(request.getStandardCost())
                        .status("ACTIVE") // 默认状态为启用
                        .description(request.getDescription())
                        .build();
                
                materialViewService.save(materialView);
                
                return R.ok(result.data(), result.msg());
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("创建物料失败", e);
            return R.fail("创建物料失败: " + e.getMessage());
        }
    }

    @Override
    public R<Page<MaterialViewPo>> list(Page<MaterialViewPo> page, MaterialViewPo query) {
        try {
            LambdaQueryWrapper<MaterialViewPo> wrapper = new LambdaQueryWrapper<>();
            
            // 构建查询条件
            if (StringUtils.hasText(query.getMaterialCode())) {
                wrapper.like(MaterialViewPo::getMaterialCode, query.getMaterialCode());
            }
            if (StringUtils.hasText(query.getMaterialName())) {
                wrapper.like(MaterialViewPo::getMaterialName, query.getMaterialName());
            }
            if (query.getGroupId() != null) {
                wrapper.eq(MaterialViewPo::getGroupId, query.getGroupId());
            }
            if (StringUtils.hasText(query.getStatus())) {
                wrapper.eq(MaterialViewPo::getStatus, query.getStatus());
            }
            
            // 默认按创建时间倒序
            wrapper.orderByDesc(MaterialViewPo::getCreatedTime);
            
            Page<MaterialViewPo> result = materialViewService.page(page, wrapper);
            return R.ok(result);
        } catch (Exception e) {
            log.error("查询物料列表失败", e);
            return R.fail("查询物料列表失败: " + e.getMessage());
        }
    }

    @Transactional
    @Override
    public R<Void> update(Long id, UpdateMaterialRequest request) {
        try {
            // 先获取当前物料信息
            MaterialViewPo currentMaterial = materialViewService.getById(id);
            if (currentMaterial == null) {
                return R.fail("物料不存在");
            }

            // 比较并执行相应的更新命令
            boolean hasError = false;
            String errorMessage = "";

            // 更新物料基本信息（名称、群组、描述）
            UpdateMaterialCommand updateCommand = new UpdateMaterialCommand(id);
            CommandResult<Void> updateResult = updateMaterialCommandHandler.handle(updateCommand);
            if (!updateResult.success()) {
                hasError = true;
                errorMessage = updateResult.msg();
            }

            // 检查规格是否变更
            if (!hasError && !java.util.Objects.equals(currentMaterial.getSpecification(), request.getSpecification())) {
                UpdateMaterialSpecificationCommand specCommand = new UpdateMaterialSpecificationCommand(
                        id, request.getSpecification());
                CommandResult<Void> specResult = updateMaterialSpecificationCommandHandler.handle(specCommand);
                if (!specResult.success()) {
                    hasError = true;
                    errorMessage = specResult.msg();
                }
            }

            // 检查计量单位是否变更
            if (!hasError && !java.util.Objects.equals(currentMaterial.getUnit(), request.getUnit())) {
                UpdateMaterialUnitCommand unitCommand = new UpdateMaterialUnitCommand(
                        id, request.getUnit());
                CommandResult<Void> unitResult = updateMaterialUnitCommandHandler.handle(unitCommand);
                if (!unitResult.success()) {
                    hasError = true;
                    errorMessage = unitResult.msg();
                }
            }

            // 检查成本是否变更
            if (!hasError && !java.util.Objects.equals(currentMaterial.getStandardCost(), request.getStandardCost())) {
                UpdateMaterialCostCommand costCommand = new UpdateMaterialCostCommand(
                        id, request.getStandardCost());
                CommandResult<Void> costResult = updateMaterialCostCommandHandler.handle(costCommand);
                if (!costResult.success()) {
                    hasError = true;
                    errorMessage = costResult.msg();
                }
            }

            if (hasError) {
                return R.fail(errorMessage);
            }

            // 更新读模型
            MaterialViewPo updatedMaterial = MaterialViewPo.builder()
                    .id(id)
                    .materialCode(currentMaterial.getMaterialCode()) // 编码不允许修改
                    .materialName(request.getMaterialName())
                    .specification(request.getSpecification())
                    .model(request.getModel())
                    .unit(request.getUnit())
                    .groupId(request.getGroupId())
                    .standardCost(request.getStandardCost())
                    .status(currentMaterial.getStatus()) // 保持原状态
                    .description(request.getDescription())
                    .build();
            
            materialViewService.updateById(updatedMaterial);

            return R.ok();
        } catch (Exception e) {
            log.error("更新物料失败", e);
            return R.fail("更新物料失败: " + e.getMessage());
        }
    }

    @Override
    public R<Void> updateSpecification(Long id, UpdateMaterialSpecificationRequest request) {
        try {
            UpdateMaterialSpecificationCommand command = new UpdateMaterialSpecificationCommand(
                    id,
                    request.getSpecification()
            );

            CommandResult<Void> result = updateMaterialSpecificationCommandHandler.handle(command);
            
            if (result.success()) {
                return R.ok();
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("更新物料规格失败", e);
            return R.fail("更新物料规格失败: " + e.getMessage());
        }
    }

    @Override
    public R<Void> updateUnit(Long id, UpdateMaterialUnitRequest request) {
        try {
            UpdateMaterialUnitCommand command = new UpdateMaterialUnitCommand(
                    id,
                    request.getUnit()
            );

            CommandResult<Void> result = updateMaterialUnitCommandHandler.handle(command);
            
            if (result.success()) {
                return R.ok();
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("更新物料单位失败", e);
            return R.fail("更新物料单位失败: " + e.getMessage());
        }
    }

    @Override
    public R<Void> updateCost(Long id, UpdateMaterialCostRequest request) {
        try {
            UpdateMaterialCostCommand command = new UpdateMaterialCostCommand(
                    id,
                    request.getStandardCost()
            );

            CommandResult<Void> result = updateMaterialCostCommandHandler.handle(command);
            
            if (result.success()) {
                return R.ok();
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("更新物料成本失败", e);
            return R.fail("更新物料成本失败: " + e.getMessage());
        }
    }

    @Override
    public R<Void> enable(Long id) {
        try {
            EnableMaterialCommand command = new EnableMaterialCommand(id);
            CommandResult<Void> result = enableMaterialCommandHandler.handle(command);
            
            if (result.success()) {
                return R.ok();
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("启用物料失败", e);
            return R.fail("启用物料失败: " + e.getMessage());
        }
    }

    @Override
    public R<Void> disable(Long id) {
        try {
            DisableMaterialCommand command = new DisableMaterialCommand(id);
            CommandResult<Void> result = disableMaterialCommandHandler.handle(command);
            
            if (result.success()) {
                return R.ok();
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("禁用物料失败", e);
            return R.fail("禁用物料失败: " + e.getMessage());
        }
    }

    @Override
    public R<Void> delete(Long id) {
        try {
            DeleteMaterialCommand command = new DeleteMaterialCommand(id);
            CommandResult<Void> result = deleteMaterialCommandHandler.handle(command);
            
            if (result.success()) {
                return R.ok();
            } else {
                return R.fail(result.msg());
            }
        } catch (Exception e) {
            log.error("删除物料失败", e);
            return R.fail("删除物料失败: " + e.getMessage());
        }
    }

    @Override
    public R<Void> batchDelete(List<Long> ids) {
        try {
            for (Long id : ids) {
                DeleteMaterialCommand command = new DeleteMaterialCommand(id);
                CommandResult<Void> result = deleteMaterialCommandHandler.handle(command);
                
                if (!result.success()) {
                    return R.fail("删除物料失败: " + result.msg());
                }
            }
            return R.ok();
        } catch (Exception e) {
            log.error("批量删除物料失败", e);
            return R.fail("批量删除物料失败: " + e.getMessage());
        }
    }

    @Override
    public R<MaterialViewPo> getById(Long id) {
        try {
            MaterialViewPo material = materialViewService.getById(id);
            if (material == null) {
                return R.fail("物料不存在");
            }
            return R.ok(material);
        } catch (Exception e) {
            log.error("获取物料详情失败", e);
            return R.fail("获取物料详情失败: " + e.getMessage());
        }
    }

    @Override
    public R<List<MaterialViewPo>> getByGroupId(Long groupId) {
        try {
            LambdaQueryWrapper<MaterialViewPo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(MaterialViewPo::getGroupId, groupId)
                   .eq(MaterialViewPo::getStatus, "ACTIVE")
                   .orderByAsc(MaterialViewPo::getMaterialCode);
            
            List<MaterialViewPo> materials = materialViewService.list(wrapper);
            return R.ok(materials);
        } catch (Exception e) {
            log.error("根据群组获取物料列表失败", e);
            return R.fail("根据群组获取物料列表失败: " + e.getMessage());
        }
    }

    @Override
    public R<List<MaterialViewPo>> getActiveList() {
        try {
            LambdaQueryWrapper<MaterialViewPo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(MaterialViewPo::getStatus, "ACTIVE")
                   .orderByAsc(MaterialViewPo::getMaterialCode);
            
            List<MaterialViewPo> materials = materialViewService.list(wrapper);
            return R.ok(materials);
        } catch (Exception e) {
            log.error("获取启用物料列表失败", e);
            return R.fail("获取启用物料列表失败: " + e.getMessage());
        }
    }
}